package com.adtech.adms.system.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.apache.log4j.Logger;

import com.adtech.adms.commons.tree.FeatureTreeNode;
import com.adtech.adms.commons.tree.TreeNode;
import com.adtech.adms.commons.util.TreeUtil;
import com.adtech.adms.commons.util.TreeUtil.OnGetNodeListener;
import com.adtech.adms.system.SystemConstants;
import com.adtech.adms.system.dao.FeatureDAO;
import com.adtech.adms.system.pojo.Feature;
import com.adtech.adms.system.pojo.Role;
import com.adtech.adms.system.pojo.User;
import com.adtech.adms.system.service.FeatureService;
import com.adtech.core.Settings;
import com.adtech.core.cache.Cache;
import com.adtech.core.dao.exp.Condition;
import com.adtech.core.dao.exp.Expression;
import com.adtech.core.dao.query.QueryConstants;
import com.adtech.core.dao.query.QueryCriterions;
import com.adtech.core.dao.query.Sort;
import com.adtech.core.exception.ServiceException;
import com.adtech.core.exception.SystemException;

/**
 * 功能模块service实现类
 * 实现功能模块业务操作
 * @author Dormin 
 * @since 2011-8-11 
 * 
 * @Copyright (C) AD Tech Workshop All Right Reserved
 */
public class FeatureServiceImpl implements FeatureService {
	
	private static final Logger log = Logger.getLogger(FeatureServiceImpl.class);

	private FeatureDAO featureDAO;
	private Cache templateCache;

	public void setFeatureDAO(FeatureDAO featureDAO) {
		this.featureDAO = featureDAO;
	}

	public void delete(Long id) throws ServiceException {
		featureDAO.delete(Feature.class, id);

	}

	public Cache getTemplateCache() {
		return templateCache;
	}

	public void setTemplateCache(Cache templateCache) {
		this.templateCache = templateCache;
	}

	public List<Feature> getFeatureList() {
		return (List<Feature>)featureDAO.getByQuery(Feature.class, null);
	}

	public List<TreeNode<Feature>> getFeatureListByUser(User user) {
		ArrayList<TreeNode<Feature>> nodes = null;
		try {
			nodes = (ArrayList<TreeNode<Feature>>) templateCache.get(user.getUserId());
		} catch (SystemException e) {
			log.error("FeatureServiceImpl.getFeatureListByUser(): SystemException", e);
		}
		if(nodes==null) {
			nodes = new ArrayList<TreeNode<Feature>>();
			List<Feature> fetures = featureDAO.getFeaturesByRoles(user.getRoles());
//			List<Feature>  fetures = null;//hyman temp 
			for (Object element : fetures) {
				Feature feature = (Feature) element;
				if(feature.getId() == 9000){
					System.out.println(feature.getParent());
				}
				if (feature.getParent() == null) {
					TreeNode<Feature> node = new FeatureTreeNode(feature);
					node.setNodes(setNodesByFeatures(node, fetures));
					nodes.add(node);
				}
			}
			if(Settings.CACHE) {
				templateCache.put(user.getUserId(),nodes);
			}
		}
		return nodes;
	}

	private List<TreeNode<Feature>> setNodesByFeatures(TreeNode<Feature> featureNode, List<Feature> fetures) {
		List<TreeNode<Feature>> nodes = new ArrayList<TreeNode<Feature>>();
		for (Feature feature1 : fetures) {
			if (feature1.getParent() != null && feature1.getParent().getId().equals(featureNode.getInnerObject().getId())) {
				FeatureTreeNode node = new FeatureTreeNode(feature1);
				node.setNodes(setNodesByFeatures(node, fetures));
				nodes.add(node);
				node.setParent(featureNode);
			}
		}
		return nodes;
	}

	public Feature getFeatureById(Long id) {
		return featureDAO.getById(Feature.class, id);
	}

	public List<TreeNode<Feature>> getFeatureTree(boolean allLevel,Role role) {
		List<TreeNode<Feature>> nodes = new ArrayList<TreeNode<Feature>>();
		QueryCriterions hc = new QueryCriterions();
		hc.and(SystemConstants.Feature.PARENT, null, QueryConstants.EQ);
		List<Feature> fetures = (List<Feature>)featureDAO.getByQuery(Feature.class, hc.toExpression(),new Sort(SystemConstants.Feature.ORDER_NUMBER, QueryConstants.ASC));
		for (Feature feature : fetures) {
			//featureDAO.initialize(feature);
			FeatureTreeNode node = new FeatureTreeNode(feature);
			if(allLevel) {
				node.setNodes(initNodes(feature.getChildren(), node));
			} else {
				if(feature.getChildren().size()>0) {
					node.setIsParent(true);
					node.setHalfChecked(isHalfChecked(feature,role));
				} else {
					node.setIsParent(false);
				}
			}
			nodes.add(node);
		}
		return nodes;
	}
	
	/**
	 * 是否此权限以及其所有子权限都被选中
	 * @param feature
	 * @return
	 * @author Dormin
	 */
	private boolean isHalfChecked(Feature feature,Role role) {
		if(role==null || role.getRoleId()==null) {
			return false;
		}
		return featureDAO.isHalfChecked(feature, role);
	}

	public List<TreeNode<Feature>> getFeatureTree(Long id) {
		List<TreeNode<Feature>> nodes = new ArrayList<TreeNode<Feature>>();
		Expression expression = Condition.eq(SystemConstants.Feature.PARENT + "." + SystemConstants.Feature.FEATURE_ID, id);
		List<Feature> fetures = (List<Feature>)featureDAO.getByQuery(Feature.class, expression,new Sort(SystemConstants.Feature.ORDER_NUMBER, QueryConstants.ASC));
		for (Feature feature : fetures) {
			featureDAO.initialize(feature);
			TreeNode<Feature> node = new FeatureTreeNode(feature);
			if (node.getInnerObject().getEntryType().byteValue() == Feature.ENTRY_TYPE_MENU) {
				nodes.add(node);
			}
			
		}
		return nodes;
	}
	
	public List<TreeNode<Feature>> getFeatureTree(User user,Long id) {
		List<TreeNode<Feature>> nodes = new ArrayList<TreeNode<Feature>>();
		Expression expression = Condition.eq(SystemConstants.Feature.PARENT + "." + SystemConstants.Feature.FEATURE_ID, id);
		List<Object> roleIdList = new ArrayList<Object>();
//		for(Role role : user.getRoles()) {
//			roleIdList.add(role.getRoleId());
//		}
		expression = Condition.and(Condition.in(SystemConstants.Feature.ROLES_ROLEID, roleIdList), expression);
		List<Feature> fetures = (List<Feature>)featureDAO.getByQuery(Feature.class, expression,new Sort(SystemConstants.Feature.ORDER_NUMBER, QueryConstants.ASC));
		List<Serializable> nodeIds = new ArrayList<Serializable>();
		for (Feature feature : fetures) {
			featureDAO.initialize(feature);
			TreeNode<Feature> node = new FeatureTreeNode(feature);
			if (node.getInnerObject().getEntryType().byteValue() == Feature.ENTRY_TYPE_MENU && !nodeIds.contains(node.getId())) {
				nodes.add(node);
				nodeIds.add(node.getId());
			}
			
		}
		return nodes;
	}

	public List<TreeNode<Feature>> getFeatureTree(Long id, boolean allLevel,Role role) {
		List<TreeNode<Feature>> nodes = new ArrayList<TreeNode<Feature>>();
		QueryCriterions hc = new QueryCriterions();
		hc.and(SystemConstants.Feature.PARENT + "." + SystemConstants.Feature.FEATURE_ID, id, QueryConstants.EQ);
		List<Feature> fetures = (List<Feature>)featureDAO.getByQuery(Feature.class, hc.toExpression(),new Sort(SystemConstants.Feature.ORDER_NUMBER, QueryConstants.ASC));
		for (Feature feature : fetures) {
			//featureDAO.initialize(feature);
			FeatureTreeNode node = new FeatureTreeNode(feature);
			if(allLevel) {
				node.setNodes(initNodes(feature.getChildren(), node));
			} else {
				if(feature.getChildren().size()>0) {
					node.setIsParent(true);
					node.setHalfChecked(isHalfChecked(feature,role));
				} else {
					node.setIsParent(false);
				}
			}
			nodes.add(node);
		}
		return nodes;
	}

	private final List<TreeNode<Feature>> initNodes(List<Feature> fetures, TreeNode<Feature> parent) {
		List<TreeNode<Feature>> nodes = null;
		if (fetures != null && fetures.size() > 0) {
			nodes = new ArrayList<TreeNode<Feature>>();
			for (Feature feature : fetures) {
				featureDAO.initialize(feature);
				TreeNode<Feature> node = new FeatureTreeNode(feature);
				node.setNodes(initNodes(feature.getChildren(), parent));
				nodes.add(node);
			}
		}
		return nodes;
	}

	public void save(Feature feature) throws ServiceException {
		if (feature.getRoot()!=null&&!feature.getRoot()) {
			QueryCriterions hc = new QueryCriterions();
			hc.and(SystemConstants.Feature.FEATURE_ID, feature.getParent().getId(), QueryConstants.EQ);
			Feature parent = featureDAO.getOneByQuery(Feature.class, hc.toExpression());
			feature.setParent(parent);
		} else {
			feature.setParent(null);
		}
		if(feature.getId()!=null){
			Feature pFeature=featureDAO.getById(Feature.class, feature.getId());
			pFeature.setName(feature.getName());
			pFeature.setCode(feature.getCode());
			pFeature.setUrl(feature.getUrl());
			pFeature.setComments(feature.getComments());
			pFeature.setUrlTarget(feature.getUrlTarget());
			pFeature.setEntryType(feature.getEntryType());
//			pFeature.setSerialNumber(feature.getSerialNumber());
			pFeature.setClasses(feature.getClasses());
			featureDAO.saveOrUpdate(pFeature);
		}
		else {
			featureDAO.saveOrUpdate(feature);
		}
	}

	public List<TreeNode<Feature>> getTreeNodeListByFeatures(List<TreeNode<Feature>> featureNodes) {
				List<TreeNode> features = new ArrayList<TreeNode>();
				for (TreeNode treeNode : featureNodes) {
					TreeNode node = TreeUtil.iteratorNodes(treeNode, new OnGetNodeListener() {
		
						public boolean onGetNode(TreeNode node) {
							FeatureTreeNode fnode = (FeatureTreeNode) node;
							if (fnode.getInnerObject().getEntryType().byteValue() == Feature.ENTRY_TYPE_MENU) {
								return true;
							}
							return false;
						}
					});
					if (node != null) {
						if (node.getParent() != null) {
							features.addAll(node.getParent().getNodes());
						} else {
							features.add(node);
						}
						break;
					}
				}
//		featureNodes = mockDate();
		Stack<TreeNode<Feature>> nodes = new Stack<TreeNode<Feature>>();

		for (TreeNode<Feature> node : featureNodes) {
			FeatureTreeNode fnode = (FeatureTreeNode) node;
			if (fnode.getInnerObject().getEntryType().byteValue() == Feature.ENTRY_TYPE_MENU) {
				FeatureTreeNode fn = new FeatureTreeNode(fnode.getInnerObject());
				fn.setNodes(initMenuNodes(node.getNodes()));
				nodes.push(fn);
			}

		}
		

		return nodes;
	}

	private final List<TreeNode<Feature>> initMenuNodes(List<TreeNode<Feature>> features) {
		Stack<TreeNode<Feature>> nodes = new Stack<TreeNode<Feature>>();
		if (features != null) {
			for (TreeNode<Feature> node : features) {
				FeatureTreeNode fnode = (FeatureTreeNode) node;
				if (fnode.getInnerObject().getEntryType().byteValue() == Feature.ENTRY_TYPE_MENU) {
					FeatureTreeNode fn = new FeatureTreeNode(fnode.getInnerObject());
					fn.setNodes(initMenuNodes(node.getNodes()));
					nodes.push(fn);
				}
			}
		}
		return nodes;
	}

	public boolean check(Feature feature){
		QueryCriterions qc = new QueryCriterions();
		qc.and(SystemConstants.Feature.CODE, feature.getCode(), QueryConstants.EQ);
		qc.and(SystemConstants.Feature.FEATURE_ID, feature.getId(), QueryConstants.NE);

		return featureDAO.getByQuery(Feature.class, qc.toExpression()).size() == 0;
	}

	/* 
	 * @see com.tdqs.pnpms.system.service.FeatureService#getSecondFeatureByCode(java.lang.String)
	 */
	@Override
	public Feature getSecondFeatureByCode(String code) {
		Expression expression = Condition.eq(SystemConstants.Feature.CODE, code);
		
		List<Feature> features = featureDAO.getByQuery(Feature.class, expression);
		
		if(features != null && features.size() > 0){
			Feature feature = features.get(0);
			return caculateSecondFeature(feature);
		}
		
		return null;
	}
	
	@Override
	public Feature getFeatureByCode(String code) {
		Expression expression = Condition.eq(SystemConstants.Feature.CODE, code);
		
		List<Feature> features = featureDAO.getByQuery(Feature.class, expression);
		
		if(features != null && features.size() > 0){
			return features.get(0);
		}
		
		return null;
	}

	private Feature caculateSecondFeature(Feature feature){
		if(feature.getParent() == null){
			//一级菜单
			return feature;
		}else if(feature.getParent().getParent() == null){
			//二级菜单
			return feature;
		}else{
			Feature seconFeature = feature.getParent();
			return caculateSecondFeature(seconFeature);
		}
	}
	private List<TreeNode<Feature>> mockDate(){
		List<TreeNode<Feature>> parentFeatureNodes = new ArrayList<TreeNode<Feature>>();
		List<TreeNode<Feature>> featureNodes1 = new ArrayList<TreeNode<Feature>>();
		List<TreeNode<Feature>> featureNodes2 = new ArrayList<TreeNode<Feature>>();
		
		Feature f11 = new Feature();
		f11.setId(1l);
		f11.setUrl("systemlog/main");
		f11.setClasses("jcsjgl");
		f11.setEntryType(Feature.ENTRY_TYPE_MENU);
		f11.setName("Device");
		
		Feature f21 = new Feature();
		f21.setId(2l);
		f21.setUrl("user/main");
		f21.setClasses("ghrwjhk");
		f21.setEntryType(Feature.ENTRY_TYPE_MENU);
		f21.setName("用户信息");

		FeatureTreeNode fnode1 = new FeatureTreeNode(f11);
		FeatureTreeNode fnode2 = new FeatureTreeNode(f21);
//		fnode.set
		featureNodes1.add(fnode1);
		featureNodes2.add(fnode2);
		
		Feature f1 = new Feature();
		f1.setId(1l);
		f1.setClasses("jczl");
		f1.setEntryType(Feature.ENTRY_TYPE_MENU);
		f1.setName("subDevice");
		
	
		FeatureTreeNode baseInfoNode = new FeatureTreeNode(f1);
		baseInfoNode.setNodes(featureNodes1);
		
		Feature f2 = new Feature();
		f2.setId(2l);
		f2.setClasses("ghyw");
		f2.setEntryType(Feature.ENTRY_TYPE_MENU);
		f2.setName("22222");
		
		FeatureTreeNode systemInfoNode = new FeatureTreeNode(f2);
		systemInfoNode.setNodes(featureNodes2);
		parentFeatureNodes.add(baseInfoNode);
		parentFeatureNodes.add(systemInfoNode);
		
		return parentFeatureNodes;
		

	}
}
